home *** CD-ROM | disk | FTP | other *** search
- {
- File: UMenuHandler.p
-
- Contains: All of the code in this module is used to maintain the menus and to handle
- menu selections by the user.
-
- Written by: Forrest Tanaka
-
- Copyright: Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/27/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- }
- UNIT UMenuHandler;
-
- {[j=20/57/1$] Pasmat Options}
-
-
- INTERFACE
-
-
- (*******************************************************************************
- * Used Units
- *******************************************************************************)
-
- USES
- (* Application *)
- UGlobals
- ,UProcessUtils
- ,UProcessGuts
- ;
-
-
- (*******************************************************************************
- * Constants
- *******************************************************************************)
-
- CONST
- mApple = 128; {Menu ID and resource ID of Apple menu}
- iAbout = 1; {Menu item number of About SevenPaint item}
-
- mFile = 129; {Menu ID and resource ID of File menu}
- iClose = 1; {Menu item number of Close item}
- iLaunchFore = 3; {Menu item number of Launch to Foreground… item}
- iLaunchBack = 4; {Menu item number of Launch to Background… item}
- iLaunchTo = 5; {Menu item number of Launch To… item}
- iJustLaunch = 7; {Menu item number of Simple Launch item}
- iOpenLaunch = 8; {Menu item number of Open Documents on Launch item}
- iPrintLaunch = 9; {Menu item number of Print Documents on Launch item}
- iQuit = 11; {Menu item number of Quit item}
-
- mProcess = 130; {Menu ID and resource ID of Process menu}
- iBringFront = 1; {Menu item number of Bring Process to Front item}
- iShowProcessInfo = 2; {Menu item number of Show Process Info item}
- iTerminateProcess = 3; {Menu item number of Terminate Process item}
-
-
- (*******************************************************************************
- * StartMenus - Do additional initialization of the menus
- *
- * This routine is called just after calling the Utilities sample code routine,
- * StandardMenuSetup. This application needs to do just a little bit of
- * additional initialization for menus. See below for details.
- *
- * If there isn’t enough memory to load the menus, then the gError global is set
- * to memFullErr. If desired menu resources couldn’t be found, then gError is
- * set to resNotFound. If any other error occurs, then gError is set to
- * dsSysErr.
- *******************************************************************************)
-
- PROCEDURE StartMenus;
-
-
- (*******************************************************************************
- * DoMenuChoice - Dispatch to the appropriate routine for a menu choice
- *
- * When it’s determined that a menu item was chosen, this routine is called to
- * dispatch to the appropriate routine for the chosen menu item. The menu item
- * and menu number returned by MenuSelect and MenuKey is passed in the menuChoice
- * parameter.
- *******************************************************************************)
-
- PROCEDURE DoMenuChoice (menuChoice: LongInt);
-
-
- (*******************************************************************************
- * FixMenus - Fix menus so that proper items are enabled and marked
- *
- * FixMenus is called to assure that menu items are disable, enabled, marked, and
- * unmarked appropriately. It’s called at the end of every iteration of the main
- * event loop.
- *******************************************************************************)
-
- PROCEDURE FixMenus;
-
-
- IMPLEMENTATION
-
- USES
- Resources
- ,Devices
- ,ToolUtils
- ;
-
- (*******************************************************************************
- * Constants
- *******************************************************************************)
-
- CONST
- rMenuBar = 128; {Resource ID of this application’s MBAR resource}
-
- mFirst = mFile; {Menu ID of the first non-Apple menu in the menu list}
- mLast = mProcess; {Menu ID of the last menu in the menu list}
-
-
- (*******************************************************************************
- * Types
- *******************************************************************************)
-
- TYPE
- MenuGuide = RECORD
- theMenu: MenuHandle; {Handle to this guide’s menu}
- enables: LongInt {Current enable flags}
- END;
-
-
- (*******************************************************************************
- * Variables
- *******************************************************************************)
-
- VAR
- gMenuGuides: ARRAY [mFirst..mLast] OF MenuGuide;
-
- {$S Startup}
- (*******************************************************************************
- * Public: StartMenus
- *
- * The menu guide array is initialized with the menu handles and enable flags of
- * all menus.
- *
- * If GetNewMBar couldn’t load the MBAR resource, then it returns NIL and the
- * error code is in ResError, and I can deal with the error elegantly. But, if
- * the GetNewMBar couldn’t load the menus themselves, then it’ll probably crash.
- *******************************************************************************)
-
- PROCEDURE StartMenus;
-
- VAR
- menuBar: Handle; {Handle to the menu bar from the MBAR resource}
- menuIndex: Integer; {Index into menu guide records}
-
- BEGIN
- (* Load in the menu bar *)
- menuBar := GetNewMBar (rMenuBar);
- IF menuBar <> NIL THEN
- BEGIN
- (* Set it, then dispose of it because SetMenuBar makes a copy *)
- SetMenuBar (menuBar);
- DisposeHandle (menuBar);
-
- (* Add the desk accessories to the Apple menu *)
- AppendResMenu (GetMenuHandle (mApple), 'DRVR');
-
- (* Initialize the menu guide array *)
- FOR menuIndex := mFile TO mProcess DO
- BEGIN
- gMenuGuides [menuIndex].theMenu := GetMenuHandle (menuIndex);
- gMenuGuides [menuIndex].enables := gMenuGuides [menuIndex].
- theMenu^^.enableFlags
- END;
-
- (* Draw the menu bar *)
- DrawMenuBar
- END
- ELSE
- IF ResError = memFullErr THEN
- gError := memFullErr
- ELSE IF (ResError = noErr) OR (ResError = resNotFound) THEN
- gError := resNotFound
- ELSE
- gError := dsSysErr
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Private: DoAppleMenu - Handle an Apple menu item choice
- *
- * This routine is called whenever it’s determined that the chosen menu item was
- * in the Apple menu. If the chosen menu item that’s passed in the menuItem
- * parameter wasn’t the About item, the name of the menu item is retrieved and
- * then OpenDeskAcc is called with this name so that the desk accessory by that
- * name is opened. The Process Manager can launch desk accessories, but
- * OpenDeskAcc should still be used if the user chooses any item in the Apple
- * menu.
- *******************************************************************************)
-
- PROCEDURE DoAppleMenu (menuItem: Integer);
-
- VAR
- daName: Str255; {Name of the chosen DA}
- refNum: Integer; {Reference number of the DA, ignored}
-
- BEGIN
- IF menuItem = iAbout THEN
- ShowAboutBox
- ELSE
- BEGIN
- GetMenuItemText (GetMenuHandle (mApple), menuItem, (*<*)daName);
- refNum := OpenDeskAcc (daName)
- END
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Private: DoFileMenu - Handle a File menu item choice
- *
- * This routine is called whenever it’s determined that the chosen menu item was
- * in the File menu. The item number of the chosen menu item is passed in the
- * menuItem parameter.
- *******************************************************************************)
-
- PROCEDURE DoFileMenu (menuItem: Integer);
-
- VAR
- junkError: OSErr;
-
- BEGIN
- CASE menuItem OF
- iClose:
- DoWindowClose(FrontWindow);
- iLaunchFore:
- DoLaunchInFront;
- iLaunchBack:
- DoLaunchInBack;
- iLaunchTo:
- DoLaunchTo;
- iJustLaunch,
- iOpenLaunch,
- iPrintLaunch:
- DoLaunchMode (menuItem);
- iQuit:
- junkError := DoQuit
- END
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Private: DoProcessMenu - Handle a Process menu item choice
- *
- * This routine is called whenever it’s determined that the chosen menu item was
- * in the Process menu. The item number of the chosen menu item is passed in the
- * menuItem parameter.
- *******************************************************************************)
-
- PROCEDURE DoProcessMenu (menuItem: Integer);
-
- BEGIN
- CASE menuItem OF
- iBringFront:
- DoBringProcessToFront (FrontWindow);
- iShowProcessInfo:
- DoGetProcessInfo (FrontWindow);
- iTerminateProcess:
- DoTerminateProcess (FrontWindow)
- END
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: DoMenuChoice
- *
- * This routine should be self-explanatory.
- *******************************************************************************)
-
- PROCEDURE DoMenuChoice (menuChoice: LongInt);
-
- VAR
- menuNum: Integer; {Menu number of chosen menu}
- menuItem: Integer; {Item number of chosen menu item}
- startTicks: longint; {TickCount when menu command started}
- BEGIN
- IF menuChoice <> 0 THEN
- BEGIN
- startTicks := TickCount;
-
- (* Get the chosen menu item and menu number *)
- menuNum := HiWord (menuChoice);
- menuItem := LoWord (menuChoice);
-
- (* Dispatch the appropriate menu-handling routine *)
- CASE menuNum OF
- mApple:
- DoAppleMenu (menuItem);
- mFile:
- DoFileMenu (menuItem);
- mProcess:
- DoProcessMenu (menuItem);
- END;
-
- WHILE TickCount < (startTicks + 6) DO BEGIN
- (* Wait to make sure menu highlighting is visible. *)
- END;
-
- IF NOT gQuitting THEN BEGIN
- HiliteMenu (0);
- END;
- END
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Private: ResetMenuItems - Disable any disableable items and clear marks
- *
- * Disabling all the menu items is done bruteforcedly. It could easily be done
- * by looping through each menu and disabling every item that comes up (disabling
- * a Font menu would be done this way), but I thought doing it using the brute-force
- * method was clearer. Then again. . .
- *******************************************************************************)
-
- PROCEDURE ResetMenuItems;
-
- VAR
- aMenu: MenuHandle; {Handle to each menu we’re disabling}
-
- BEGIN
- (* Disable items in the File menu *)
- aMenu := GetMenuHandle (mFile);
- DisableItem (aMenu, iClose);
- DisableItem (aMenu, iLaunchFore);
- DisableItem (aMenu, iLaunchBack);
- DisableItem (aMenu, iLaunchTo);
- SetItemMark (aMenu, iJustLaunch, CHR (noMark));
- SetItemMark (aMenu, iOpenLaunch, CHR (noMark));
- SetItemMark (aMenu, iPrintLaunch, CHR (noMark));
-
- (* Disable items in the Process menu *)
- aMenu := GetMenuHandle (mProcess);
- DisableItem (aMenu, iBringFront);
- DisableItem (aMenu, iShowProcessInfo);
- DisableItem (aMenu, iTerminateProcess);
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: FixMenus
- *
- * FixMenus first disables every available menu item. Then the most basic menu
- * items are enabled. The windowKind field of the front window is then checked.
- * If there is a window open, FixMenus calls a routine that’s responsible for
- * that kind of window to enable any menu items that are relevant to that kind of
- * window.
- *
- * After this is done, the menu bar might have to be redrawn to reflect the new
- * conditions. So, FixMenus go through every menu to determine if the state of
- * the entire menu has changed. The MenuGuide records are used to help determine
- * this. If the state of any many has changed, then the menu bar is redrawn.
- *******************************************************************************)
-
- PROCEDURE FixMenus;
-
- VAR
- currWindow: WindowPtr; {Pointer to the front-most window}
- currMenu: MenuHandle; {Handle to menu being enabled}
- oldEnables: LongInt; {True if 1+ menu items enabled when FixMenus called}
- newEnables: LongInt; {True if 1+ menu items enabled after menus fixed}
- mustRedraw: Boolean; {TRUE if menu bar has to be redrawn}
- numItems: Integer; {Number of items in a menu}
- menuIndex: Integer; {Index into menu guide array}
-
- BEGIN
- (* Start by disabling all menus *)
- ResetMenuItems;
-
- (* Front-most window determines most menu enabling/disabling *)
- currWindow := FrontWindow;
-
- (* Fix the marks for the launch mode items *)
- currMenu := GetMenuHandle (mFile);
- CASE GetLaunchMode OF
- kJustLaunch:
- CheckItem (currMenu, iJustLaunch, TRUE);
- kOpenLaunch:
- CheckItem (currMenu, iOpenLaunch, TRUE);
- kPrintLaunch:
- CheckItem (currMenu, iPrintLaunch, TRUE)
- END;
-
- (* Enable any window-specific menu items *)
- IF currWindow <> NIL THEN
- IF IsProcessListWindow (currWindow) THEN
- (* Process list window in front, set up menu items in it *)
- FixProcessListMenus (currWindow)
- ELSE IF IsProcessInfoWindow (currWindow) THEN
- (* Process info window in front, set up menu items in it *)
- FixProcessInfoMenus (currWindow);
-
- (* Assume we don’t have to redraw the menu bar *)
- mustRedraw := FALSE;
-
- (* Check through every menu to see if there are any enabled items in it *)
- FOR menuIndex := mFirst TO mLast DO
- BEGIN
- (* Grab the old and new enable flags excluding the flag for the entire menu *)
- oldEnables := BAnd (gMenuGuides [menuIndex].enables, $FFFFFFFE);
- newEnables := BAnd (gMenuGuides [menuIndex].theMenu^^.enableFlags,
- $FFFFFFFE);
-
- (* Shift left so that we only see flags for existing items *)
- numItems := CountMItems (gMenuGuides [menuIndex].theMenu);
- oldEnables := BitShift (oldEnables, 31 - numItems);
- newEnables := BitShift (newEnables, 31 - numItems);
-
- (* Determine if the menu bar must be redrawn *)
- IF (oldEnables <> 0) AND (newEnables = 0) THEN
- BEGIN
- (* Had some items enabled, now has no items enabled, redraw *)
- DisableItem (gMenuGuides [menuIndex].theMenu, 0);
- mustRedraw := TRUE
- END
- ELSE IF (oldEnables = 0) AND (newEnables <> 0) THEN
- BEGIN
- (* Had no items enabled, now has some items enabled, redraw *)
- EnableItem (gMenuGuides [menuIndex].theMenu, 0);
- mustRedraw := TRUE
- END;
-
- (* Update our copy of the enable flags *)
- gMenuGuides [menuIndex].enables := gMenuGuides [menuIndex].
- theMenu^^.enableFlags
- END;
-
- (* If at least one menu has changed state, must redraw the menu bar *)
- IF mustRedraw THEN
- InvalMenuBar
- END;
-
- END.
-